﻿using SevenZip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace NetCommon
{
    /// <summary>
    /// 压缩解压 
    /// 使用7Zip中的LZMA算法
    /// 文件和byte[]压缩解压
    /// </summary>
    public class CompressEncoding
    {
        #region LZMA Compress
        /// <summary>
        /// 压缩byte[] 数据，输出byte[]
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        public static byte[] Encode(byte[] buff, SevenZip.ICodeProgress progress = null)
        {
            SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();
            using (MemoryStream inStream = new MemoryStream(buff))
            using (MemoryStream outStream = new MemoryStream())
            {
                //写入5位 Coder 属性
                coder.WriteCoderProperties(outStream);
                //写入4位，压缩文件长度
                outStream.Write(BitConverter.GetBytes((int)inStream.Length), 0, 4);
                //压缩编码并输出到输出目标
                coder.Code(inStream, outStream, inStream.Length, -1, progress);

                buff = outStream.ToArray();
                outStream.Close();
                inStream.Close();
            }
            return buff;
        }

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="inFilePath">需要压缩的文件路径</param>
        /// <param name="outFilePath">压缩后输出文件路径</param>
        /// <param name="progress"></param>
        public static void Encode(string inFilePath, string outFilePath, SevenZip.ICodeProgress progress = null)
        {
            SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();
            using (FileStream inStream = new FileStream(inFilePath, FileMode.Open))
            using (FileStream outStream = new FileStream(outFilePath, FileMode.Create))
            {
                //写入5位 Coder 属性
                coder.WriteCoderProperties(outStream);
                //写入4位，压缩文件长度
                outStream.Write(BitConverter.GetBytes((int)inStream.Length), 0, 4);
                //压缩编码并输出到输出目标
                coder.Code(inStream, outStream, inStream.Length, -1, progress);

                outStream.Flush();
                outStream.Close();
                inStream.Close();
            }
        }

        /// <summary>
        /// 解压byte[], 输出 byte[]
        /// </summary>
        /// <param name="buff"></param>
        /// <param name="progress"></param>
        /// <returns></returns>
        public static byte[] Decode(byte[] buff, SevenZip.ICodeProgress progress = null)
        {
            SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
            using (MemoryStream inStream = new MemoryStream(buff))
            using (MemoryStream outStream = new MemoryStream())
            {
                //读取5位 Coder 属性
                byte[] properties = new byte[5];
                inStream.Read(properties, 0, 5);
                //读取4位，二进制数据长度
                byte[] fileLength = new byte[4];
                inStream.Read(fileLength, 0, 4);
                //计算二进制数据长度
                int len = BitConverter.ToInt32(fileLength, 0);

                //解压缩文件，并输出到目标
                coder.SetDecoderProperties(properties);
                coder.Code(inStream, outStream, inStream.Length, len, progress);

                buff = outStream.ToArray();
                outStream.Close();
                inStream.Close();
            }
            return buff;
        }

        /// <summary>
        /// 解压文件
        /// </summary>
        /// <param name="inFilePath"></param>
        /// <param name="outFilePath"></param>
        /// <param name="progress"></param>
        public static void Decode(string inFilePath, string outFilePath, SevenZip.ICodeProgress progress = null)
        {
            SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
            using (FileStream inStream = new FileStream(inFilePath, FileMode.Open))
            using (FileStream outStream = new FileStream(outFilePath, FileMode.Create))
            {
                //读取5位 Coder 属性
                byte[] properties = new byte[5];
                inStream.Read(properties, 0, 5);
                //读取4位，二进制数据长度
                byte[] fileLength = new byte[4];
                inStream.Read(fileLength, 0, 4);
                //计算二进制数据长度
                int len = BitConverter.ToInt32(fileLength, 0);

                //解压缩文件，并输出到目标
                coder.SetDecoderProperties(properties);
                coder.Code(inStream, outStream, inStream.Length, len, progress);

                outStream.Flush();
                outStream.Close();
                inStream.Close();
            }
        }


        #endregion
    }

}
